package com.cdream.basic.thread;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ArrayUtil;

import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;

/**
 * 为啥产出一个挂起的呢？
 * 在线程刚要将自己挂起的时候，其他线线程完成了任务，把队列内容弹出了，所以自己被挂起也没人唤醒了
 * @author cdream
 * @date 2021/9/17
 */
public class CdreamLock {
    /**
     * atomic 能保证可见性，成员变量value是 volatile 的
     */
    AtomicInteger state = new AtomicInteger(0);
    private final ConcurrentLinkedDeque<Thread> waitThreads = new ConcurrentLinkedDeque<>();
    /**
     * 线程拥有者
     */
    private transient Thread own;

    private AtomicInteger park = new AtomicInteger(0);
    private AtomicInteger unpark = new AtomicInteger(0);

    public void lock() {
        if (acquire()) {
            return;
        }
        Thread current = Thread.currentThread();
        waitThreads.add(current);
        for (; ; ) {
            if (acquire()) {
                return;
            }
            park.addAndGet(1);
            LockSupport.park();
        }
    }

    public void unLock() {
        if (Thread.currentThread() != own) {
            throw new RuntimeException("????");
        }
        if (state.compareAndSet(1, 0)) {
            this.own = null;
            Thread poll = waitThreads.poll();
            if (poll != null) {
                LockSupport.unpark(poll);
                unpark.addAndGet(1);
            }
        }
    }

    /**
     * 获取锁
     */
    private boolean acquire() {
        if (state.compareAndSet(0, 1)) {
            this.own = Thread.currentThread();
            return true;
        }
        return false;
    }
    private static int[] i= new int[]{0};
    public static void main(String[] args) throws InterruptedException {
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        MyThread t3 = new MyThread();
        t1.start();
        t2.start();
        t3.start();
        monitor(t1,t2,t3);
        t1.join();
        t2.join();
        t3.join();
        System.out.println(MyThread.count);
    }
    public static void monitor(Thread ...threads){
        while (true){
            ThreadUtil.sleep(2000);

            System.out.println(ArrayUtil.toString(threads));
        }
    }


}
class MyThread extends Thread{
    public static int count;
    private static CdreamLock lock = new CdreamLock();
    @Override
    public void run() {
        for (int i = 0; i < 15; i++) {
            ThreadUtil.sleep(300);
            try {
                lock.lock();
                System.out.println(Thread.currentThread().getName()+"  "+ count++);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unLock();
            }
        }
    }
}
